<!DOCTYPE html>
<meta http-equiv=Content-Type content=text/html; charset=UTF-8> 
<style id="system" type="text/css">*{margin:0;padding:0;}
 #wrapper{min-width: 250px; max-width: 800px; margin: 15px auto;} 
 html { font-size: 100%; overflow-y: scroll; -webkit-text-size-adjust: 100%; -ms-text-size-adjust: 100%; background:#eeeeee;}
 body {	font:15px helvetica,arial,freesans,clean,sans-serif;	color:black;	line-height:1.4em;	background-color: #FFF;	padding: 0.7em;}
 p {	margin:1em 0;	line-height:1.5em;}
 table {	font-size:inherit;	font:100%;	margin:1em;}
 table th{border-bottom:1px solid #bbb;padding:.2em 1em;}
 table td{border-bottom:1px solid #ddd;padding:.2em 1em;}
  .box { text-align:center }
 input[type=text],input[type=password],input[type=image],textarea{font:99% helvetica,arial,freesans,sans-serif;}
 select,option{padding:0 .25em;}
 optgroup{margin-top:.5em;}
 pre,code{font:14px helvetica, arial,freesans,clean,sans-serif}
 pre {	margin:1em 0;	font-size:14px;	background-color:#eee;	border:1px solid #ddd;	padding:5px;	line-height:1.5em;	color:#444;	overflow:auto;	-webkit-box-shadow:rgba(0,0,0,0.07) 0 1px 2px inset;	-webkit-border-radius:3px;	-moz-border-radius:3px;border-radius:3px;}
 pre code {	padding:0;	font-size:14px;	background-color:#eee;	border:none;}
 code {	font-size:14px;	background-color:#eee;	color:#d14; pading:2px 4px border:1px solid #elele8;border-radius:3px}
 img{border:0;max-width:100%;}
 abbr{border-bottom:none;}
 a{color:#4183c4;text-decoration:none;}
 a:hover{text-decoration:underline;}
 a code,a:link code,a:visited code{color:#4183c4;}
 h2,h3{margin:1em 0;}
 h1,h2,h3,h4,h5,h6{border:0;}
 h1{font-size:170%;border-bottom:3px solid #aaa;padding-top:.5em;padding-bottom:.5em;margin-top:1.5em;}
 h1:first-child{margin-top:0;padding-bottom:.25em;border-top:none;}
 h2{font-size:150%;margin-top:1.5em;border-bottom:3px solid #e0e0e0;padding-bottom:0.5em;}
 h3{margin-top:1em;}
 hr{border:1px solid #ddd;}
 ul{margin:1em 0 1em 2em;}
 ol{margin:1em 0 1em 2em;}
 ul li,ol li{margin-top:.5em;margin-bottom:.5em;}
 ul ul,ul ol,ol ol,ol ul{margin-top:0;margin-bottom:0;}
 blockquote{margin:1em 0;border-left:5px solid #ddd;padding-left:.6em;color:#555;}
 dt{font-weight:bold;margin-left:1em;}
 dd{margin-left:2em;margin-bottom:1em;}
 @media screen and (min-width: 800px) {    body {        width: 860px;        margin:10px auto;    }
  </style><style id="custom" type="text/css"></style></head> <body marginheight="0"><div id=wrapper><p>NAT444公有地址和私有地址的映射
</p><p>
</p><ul><ul><p>nat444的解析与radius认证模块的逻辑关系
</p></ul></ul><ul><ul><p>
</p></ul></ul><h2>需求场景</h2>
<p>
</p><p>应用环境，学习radius认证报文，关联到用户报文，并打印用户信息到用户报文。在此环境下，有经过nat444转换ip地址的情况。为了把这一部分转换之后的ip关联到用户信息，有了本文档。
</p><p>
</p><h2>NAT444 溯源方式</h2>
<p>
</p><p><b>1</b>. syslog
</p><p>
</p><blockquote>
<p>日志格式有中国电信，中国联通两种格式
</p></blockquote>
<p>
</p><ul>
<li><p>用户在AAA行为中使用 <font color=#DD1144>私有地址</font> 
</p></li>

</ul>
<ul>
<li><p>在上网时候使用公有ip地址
</p></li>

</ul>
<ul>
<li><p>syslog中包含log服务器地址，私有地址，公有地址和端口块
</p></li>

</ul>
<p><b>2</b>. 静态ip映射算法
</p><p>
</p><p><b>3</b>. radius属性上报方式
</p><p>
</p><h2>方案</h2>
<p>
</p><h3>方案1</h3>
<p>
</p><p>在原有的radius版本基础上，在ip-name映射表中，加入公有地址、端口块成员。
</p><p>
</p><ul>
<li><p>首先建立ip-name映射表
</p></li>

</ul>
<ul>
<li><p>学习log报文，替换成公有地址、填充端口块信息，然后根据公有地址重新建立ip-name映射表。
</p></li>

</ul>
<ul>
<li><p>查找,在ip相同情况下判断端口块是否设置，如果没有设置就认为是公有ip直接返回查找到，如果设置了就继续判断端口是否在端口块范围内；
</p></li>

</ul>
<h4>优点：</h4>
<p>
</p><ul>
<li><p>没有添加新的映射表
</p></li>

</ul>
<h4>缺点:</h4>
<p>
</p><ul>
<li><p>公有ip会对应多个私有地址，会造成hash冲突影响性能。因为结构比较大离散存储，多次进行内存访问，影响很大
</p></li>

</ul>
<ul>
<li><p>对于ip-name多一次拆解
</p></li>

</ul>
<h4>不可用场景</h4>
<p>
</p><ul>
<li><p>log报文先流过设备，查找替换ip-name时没有查找到，这样用户报文就无法关联到用户信息
</p></li>

</ul>
<ul>
<li><p>无法扩展对于静态映射的情况
</p></li>

</ul>
<h3>方案2：</h3>
<p>
</p><p>新增一个ip_pri-ip_pub的映射表
</p><p>
</p><ul>
<li><p>根据radius报文建立ip-name映射表
</p></li>

</ul>
<ul>
<li><p>根据log报文建立ip-ip表
</p></li>

</ul>
<ul>
<li><p>使用用户ip、对应端口值首去搜索ip-ip表，查找对应的私有地址
</p></li>

</ul>
<ul>
<li><p>使用查找到的私有地址，再去查找ip-name表
</p></li>
<blockquote>
<p>可以先查找ip-name表，在未查找的情况下去查找ip-ip，然后再反查ip-name.这样在转换地址较少的情况性能比较高
</p></blockquote>

</ul>
<h4>优点：</h4>
<p>
</p><ul>
<li><p>对原有结构没有改动
</p></li>

</ul>
<ul>
<li><p>结构比较小，内存访问次数较少
</p></li>

</ul>
<h4>缺点：</h4>
<p>
</p><ul>
<li><p>查找两次表的性能消耗
</p></li>

</ul>
<h2>概要设计</h2>
<p>
</p><p>根据优缺点选定方案2-新增一个ip_pri --- ip_pub的映射表，在直接查找ip-name表没有查找到后，根据ip-ip表转换后再次查找ip-name表。
</p><p>
</p><p><div class=box><img src=/png/nat444-flow.png></div>
</p><p>
</p><h3>ip-name表</h3>
<p>
</p><p>ip-name表的操作不变，保持旧版本的方式。
</p><p>
</p><h3>ip-ip结构</h3>
<p>
</p><p><b>1</b>. ip-ip chunk结构：
</p><p>
</p><pre><p>	typedef struct _nat_ip_map {
			uint32_t 	ip_pub;		/**< public ip addr */
			uint16_t	pt_start;		/**< start port */
			uint16_t	pt_end;		/**< end port */
			uint32_t	ip_pri;		/**< private ip addr */
	} __attribute__((packed)) nat_ip_map_t;
	
	#define	IP_MAP_NUM_PER_CHCUNK	((CVMX_CACHE_LINE_SIZE - sizeof(void *)) / sizeof(nat_ip_map_t))
	
	typedef struct _nat_ip_chunk {
		nat_ip_map_t			ip_map[IP_MAP_NUM_PER_CHCUNK];
		struct _nat_ip_chunk	*next;
	} __attribute__((packed)) nat_ip_chunk_t;
</pre></p><p>
</p><p><b>2</b>. ip-ip头指针结构：
</p><pre><p>	typedef struct {
		cvmx_spinlock_t		spinlock;
		nat_ip_chunk_t		*next;
	} hash_list_head_t;
</pre></p><p>
</p><h3>ip-ip表操作</h3>
<p>
</p><p><b>1</b>. create
</p><p>
</p><ul><p>根据syslog报文，学习ip-ip的映射关系
</p></ul><ul><p>
</p></ul><p><b>2</b>. read
</p><p>
</p><ul><p>使用用户ip，加上用户端口，去查找ip-ip表
</p></ul><p>
</p><p><b>3</b>. delete
</p><p>
</p><ul><p>删除，不设置超时删除
</p></ul><ul><p>
</p></ul><ul><p>提供主动删除全部的操作接口
</p></ul><ul><p>
</p></ul><p><b>4</b>. update
</p><ul><p>
</p></ul><ul><p>更新条件：相同公有地址，端口有交叉
</p></ul><p>
</p><h3>三种ip映射方式的兼容与切换</h3>
<p>
</p><p>支持把在同一版本中切换ip映射的三种方式，1. 静态算法，2. 电信日志，3. 联通日志
</p><p>
</p><p>提供切换的接口：radius mode set 1;radius mode get
</p><p>
</p><hr><p align=right>Edit By<a href="mailto:sqm2050@gmail.com"> sqm</a></p></div>